package com.idbk.chargestation.fragment;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.CameraPosition;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.android.volley.VolleyError;
import com.idbk.chargestation.AppContext;
import com.idbk.chargestation.R;
import com.idbk.chargestation.activity.pile.ActivityKeyWordSearch;
import com.idbk.chargestation.activity.pile.ActivityPointList;
import com.idbk.chargestation.activity.user.ActivityPointCollection;
import com.idbk.chargestation.amap.base.BaseMapFragment;
import com.idbk.chargestation.api.ChargeStationAPI;
import com.idbk.chargestation.bean.JsonPointsList;
import com.idbk.chargestation.bean.JsonPointsOverview;
import com.idbk.chargestation.bll.PointFilter;
import com.idbk.chargestation.bll.PointFilter.PointFilterModel;
import com.idbk.chargestation.bll.pile.PileVendors;
import com.idbk.chargestation.dialog.DialogPointFilter;
import com.idbk.chargestation.dialog.DialogPointInfo;
import com.idbk.chargestation.net.EHttpResponse;
import com.idbk.chargestation.util.CheckUtil;
import com.idbk.chargestation.util.Const;
import com.idbk.chargestation.util.GlobalResult;
import com.idbk.chargestation.util.GsonUtils;
import com.idbk.chargestation.util.MarkerCluster;
import com.lcw.citylist.ActivityCityList;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

/**
 * @author lupc, zhx
 */
public class FragmentMap extends BaseMapFragment {

    private final static String TAG = FragmentMap.class.getSimpleName();

    /**
     * 定义一些消息常量
     */
    private final static int MSG_DECODE_DATA_FINISH = 7005;
    private final static int MSG_CREATE_MARKERS_BEGIN = 7006;
    private final static int MSG_CREATE_MARKERS_FINISH = 7007;
    private final static int MSG_ERROR_INFO = 7008;

    private Context mContext;

    //声明变量
    private View mBaseView;

    /**
     * 从服务器获取的所有充电点的数据
     */
    private JsonPointsList mData;

    private boolean isFirstLocation = true;

    private TextView mTextCity;

    private TipHandler mTipHandler;

    /**
     * marker对应的 资源描述<br/>
     * 主键：供应商id
     */
    private SparseArray<BitmapDescriptor> mBDOff = new SparseArray<BitmapDescriptor>(16);
    /**
     * 当前显示信息窗 的点
     */
    private JsonPointsOverview mCurrentPoint;

    private ProgressDialog mProgressDialog;
    /**
     * 充电点过滤器
     */
    private PointFilter.PointFilterModel mPointFilterModel;


    /**
     * 标志位：是否正在刷新
     */
    private boolean mFlagIsRefreshing = false;
    /**
     * 标志位：是否重新定位
     */
    private boolean isRepeatLocation = false;

    //网络错误显示及显示内容
    private TextView mErrorTip;
    /**
     * 当前位置
     */
    public static String locationAddress;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        mContext = getActivity();

        mBaseView = inflater.inflate(R.layout.fragment_map, container, false);

        initView(savedInstanceState);

        mTipHandler = new TipHandler(this);

        initData();

        return mBaseView;
    }

    /**
     * 高德地图定位监听
     */
    private AMapLocationListener locationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation location) {
//            Log.d(TAG, "Location 回调");
            disposeLocationChanged(location);
        }
    };

    private void disposeLocationChanged(AMapLocation location) {
        if (null != location) {
            locationManage(location);

        } else {
            Log.e("AmapErr", "location = null");
        }
    }

    private void locationManage(AMapLocation location) {
        if (location.getErrorCode() == 0) {
            //errCode等于0代表定位成功，其他的为定位失败
            // 具体的可以参照官网定位错误码说明
            locationSuccess(location);

        } else {
            //定位失败
            locationFailed(location);
        }
    }

    private void locationFailed(AMapLocation location) {
        Log.e("AmapErr", "Location ERR: " + location.getErrorCode());
        hideProgressBar();
    }

    private void locationSuccess(AMapLocation location) {
        double geoLat = location.getLatitude();
        double geoLng = location.getLongitude();
        LatLng currentLatLng = new LatLng(geoLat, geoLng);
        AppContext.getInstance().setLocation(geoLat, geoLng);
        locationAddress = "当前位置 : " + location.getAddress();
//        Log.d(TAG, "locationSuccess: getAddress  " +  location.getAddress());

        //如果是第一次定位，则移动相机,判断城市是否变化
        if (isFirstLocation) {
            firstLocation(location, currentLatLng);
        }
        if (isRepeatLocation) {
            repeatLocation(currentLatLng);
        }
    }

    private void repeatLocation(LatLng currentLatLng) {
        aMap.animateCamera(CameraUpdateFactory.changeLatLng(currentLatLng));
        isRepeatLocation = false;
        hideProgressBar();
    }

    private void firstLocation(AMapLocation location, LatLng currentLatLng) {
        isFirstLocation = false;
        animateCamera(currentLatLng);
        switchCity(location);
    }

    private void animateCamera(LatLng currentLatLng) {
        aMap.animateCamera(CameraUpdateFactory.changeTilt(0));//设定固定倾斜角度
        aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 12));
    }

    private void switchCity(AMapLocation location) {
        String cityNow = location.getCity();
        String cityPre = AppContext.getInstance().getCurrentCityName();
        if (whetherDifferentCity(cityNow, cityPre)) {
            showSwitchDialog(cityNow, cityPre);
        }
    }

    private boolean whetherDifferentCity(String cityNow, String cityPre) {
        return !cityNow.equals(cityPre) &&
                !cityNow.contains(cityPre) &&
                !cityPre.contains(cityNow);
    }

    private void showSwitchDialog(final String cityNow, String cityPre) {
        String str = String.format(
                "当前定位城市是 <font color='#5dd139'>%s</font>,选择的城市是 <font color='#5dd139'>%s</font>，是否需要切换？",
                cityNow,
                cityPre);
        new AlertDialog.Builder(mContext)
                .setMessage(CheckUtil.textFromHtml(str))
                .setCancelable(false)
                .setNegativeButton(R.string.common_cancel, null)
                .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        mTextCity.setText(cityNow);
                        AppContext.getInstance().setCurrentCityName(cityNow);
                    }
                })
                .create()
                .show();
    }

    private void initView(Bundle savedInstanceState) {
        initMapView(savedInstanceState, mBaseView);
        initLocation(mContext, locationListener);
        initWidgetView();
        initOnClickView();
    }

    private void initWidgetView() {
        mTextCity = (TextView) mBaseView.findViewById(R.id.textview_city);
        mErrorTip = (TextView) mBaseView.findViewById(R.id.textview_error);
    }

    private void initOnClickView() {
        mBaseView.findViewById(R.id.layout_city).setOnClickListener(this);
        mBaseView.findViewById(R.id.fragmentmap_textview_search).setOnClickListener(this);
        mBaseView.findViewById(R.id.imageview_list).setOnClickListener(this);
        mBaseView.findViewById(R.id.imagebutton_location).setOnClickListener(this);
        mBaseView.findViewById(R.id.imagebutton_filter).setOnClickListener(this);
        mBaseView.findViewById(R.id.refresh).setOnClickListener(this);
        mErrorTip.setOnClickListener(this);
        mBaseView.findViewById(R.id.imagebutton_nearby).setOnClickListener(this);
    }

    private void initData() {
        locationAddress = "当前位置 ： 定位失败，无法获取";
        mTextCity.setText(AppContext.getInstance().getCurrentCityName());
        mPointFilterModel = new PointFilterModel();
        refreshData();
    }

    private void refreshData() {
        if (!mFlagIsRefreshing) {
            mFlagIsRefreshing = true;
            mErrorTip.setVisibility(View.GONE);
            showProgressBar("正在下载充电点数据");
            ChargeStationAPI.getPointsOverview(mResponse); // 发送数据请求
        } else {
            Snackbar.make(mBaseView, "还在执行中，请稍后再刷新！", Snackbar.LENGTH_SHORT).show();
        }
    }

    private final EHttpResponse mResponse = new EHttpResponse() {

        @Override
        public void onEResponse(final String response) {
            Log.d(TAG, "接收数据成功");
            //开始解析数据
            showProgressBar("正在解析数据");
            //返回数据成功
            new Thread(new Runnable() {

                @Override
                public void run() {
                    //解析返回的数据
                    mData = GsonUtils.toBean(JsonPointsList.class, response);
                    mTipHandler.sendEmptyMessage(MSG_DECODE_DATA_FINISH);
                }
            }).start();
        }

        @Override
        public void onEErrorResponse(VolleyError error) {
            errorResponse();
        }
    };

    private void errorResponse() {
        Log.d(TAG, "接收数据失败");
        mFlagIsRefreshing = false;
        hideProgressBar();
        mErrorTip.setText("数据加载失败，点击重试！");
        mErrorTip.setVisibility(View.VISIBLE);
    }

    public void showProgressBar(String msg) {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(mContext);
            mProgressDialog.setMessage(msg);
            mProgressDialog.setCanceledOnTouchOutside(false);

        } else {
            mProgressDialog.setMessage(msg);
        }
        mProgressDialog.show();
    }

    public void hideProgressBar() {
        mProgressDialog.hide();
    }

    private void resetMarkers(final boolean showLoading) {
        if (mPreZoom == -1) {
            return;
        }
        //如果当前没有在执行聚合，则开始聚合
        if (!mFlagIsClustering) {
            doMarkerCluster(showLoading);
        }
    }

    private void doMarkerCluster(final boolean showLoading) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                mFlagIsClustering = true;
                //执行聚合前，记录聚合依照的缩放等级
                mZoomTemp = mPreZoom;
                if (showLoading) {
                    mTipHandler.sendEmptyMessage(MSG_CREATE_MARKERS_BEGIN);
                }
                if (mZoomTemp < ZOOM_LIMIT) {
                    addMarksWithCluster();
                } else {
                    addMarkers();
                }
                //标注生成完毕
                mTipHandler.sendEmptyMessage(MSG_CREATE_MARKERS_FINISH);

                //执行完毕后，判断当前缩放等级是否已经改变，如果改变，则重新聚合
                if (mPreZoom != mZoomTemp) {
                    doMarkerCluster(showLoading);
                }

                mFlagIsClustering = false;
            }
        }).start();
    }

    private synchronized void addMarkers() {
        aMap.clear();
        if (mData == null || mData.points == null) {
            sendErrorMessage("数据错误！");
            return;
        }
        for (JsonPointsOverview point : mData.points) {
            //运营商过滤
            if (PointFilter.isPointFiltered(point, mPointFilterModel)) {
                continue;
            }
            BitmapDescriptor b = getOperatorIcon(point.operatorId);
            //创建option对象，并初始化相关属性
            MarkerOptions markerOption = new MarkerOptions()
                    .position(new LatLng(point.lat, point.lng))
                    .draggable(false)//点标记是否可拖拽
                    .title(point.name)
                    .icon(b);

            Marker marker = aMap.addMarker(markerOption);
            marker.setObject(point);
        }
    }

    private BitmapDescriptor getOperatorIcon(int operatorId) {
        BitmapDescriptor b = mBDOff.get(operatorId);
        if (b == null) {
            b = getBitmapDescriptor(operatorId);
            mBDOff.put(operatorId, b);
        }
        return b;
    }

    private BitmapDescriptor getBitmapDescriptor(int operatorId) {
        PileVendors vendors = new PileVendors(mContext);
        Bitmap bmp = BitmapFactory
                .decodeResource(mContext.getResources(), vendors.getMarkerIcon(operatorId));
        return BitmapDescriptorFactory.fromBitmap(bmp);
    }

    /**
     * 添加支持 点聚合 的markers
     */
    private synchronized void addMarksWithCluster() {
        Log.i(TAG, "开始计算点聚合");
        //自定义的聚合类MarkerCluster
        ArrayList<MarkerCluster> clusterMarkers = new ArrayList<MarkerCluster>();
//        按照一定规则 将所有的点聚合
        convertPointsToClusterMarkers(clusterMarkers);
        Log.i(TAG, "结束聚合运算，开始生成图标并添加到地图");
        aMap.clear();
        //聚类完成后，开始生成对应的图标并添加到地图上去
        Log.e(TAG, "addMarksWithCluster clusterMarkers: " + clusterMarkers.size());
        for (MarkerCluster cluster : clusterMarkers) {
            cluster.finish();
            Marker marker = aMap.addMarker(cluster.getOptions());
            marker.setObject(cluster.getUserData());
        }
        Log.i(TAG, "结束生成图标和添加到地图");
    }


    private void convertPointsToClusterMarkers(ArrayList<MarkerCluster> clusterMarkers) {
        if (mData == null || mData.points == null) {
            sendErrorMessage("数据错误！");
            return;
        }
        for (JsonPointsOverview point : mData.points) {
            //过滤
            if (PointFilter.isPointFiltered(point, mPointFilterModel)) {
                continue;
            }
            //如果为0，则直接添加
            if (clusterMarkers.size() == 0) {
                LatLng latLng = new LatLng(point.lat, point.lng);
                MarkerCluster cluster = new MarkerCluster(mContext, latLng, aMap.getProjection());
                clusterMarkers.add(cluster);
                continue;
            }
            //接下来继续
            LatLng ll = new LatLng(point.lat, point.lng);
            MarkerCluster cluster = getCluster(ll, clusterMarkers);
            if (cluster != null) {
                //此时点合并了
                cluster.addMarker(new LatLng(point.lat, point.lng));
            } else {
                //点没有合并，则新添加一个聚合对象
                LatLng latLng = new LatLng(point.lat, point.lng);
                cluster = new MarkerCluster(mContext, latLng, aMap.getProjection());
                clusterMarkers.add(cluster);
            }
        }

    }

    private MarkerCluster getCluster(LatLng ll, ArrayList<MarkerCluster> clusterMarker) {
        for (MarkerCluster cluster : clusterMarker) {
            if (cluster.containPoint(ll)) {
                return cluster;
            }
        }
        return null;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == Const.CODE_REQUEST_LOCATE && resultCode == Const.CODE_REQUEST_LOCATE_SUCCESS) {
            Bundle bundle = data.getExtras();
            double lat = bundle.getDouble(ActivityPointCollection.FROM_SEARCH_LIST_LAT);
            double lon = bundle.getDouble(ActivityPointCollection.FROM_SEARCH_LIST_LON);
            aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 16));
        } else if (requestCode == Const.CODE_REQUEST_POINT && resultCode == Activity.RESULT_OK) {
            Log.e(TAG, "onActivityResult: requestCode :" + requestCode);

        } else if (requestCode == Const.CODE_REQUEST_CITY && resultCode == Activity.RESULT_OK) {
            String city = data.getStringExtra(Const.KEY_CITY);
            AppContext.getInstance().setCurrentCityName(city);
            mTextCity.setText(city);
        }
    }

    private void sendErrorMessage(String error) {
        Message message = mTipHandler.obtainMessage(MSG_ERROR_INFO, error);
        message.sendToTarget();
    }

    private static class TipHandler extends Handler {

        private WeakReference<FragmentMap> mFrag;

        private TipHandler(FragmentMap frag) {
            mFrag = new WeakReference<FragmentMap>(frag);
        }

        @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_DECODE_DATA_FINISH:
                    mFrag.get().hFinishDecodeData();
                    break;
                case MSG_CREATE_MARKERS_BEGIN:
                    mFrag.get().showProgressBar("正在生成标注");
                    break;
                case MSG_CREATE_MARKERS_FINISH:
                    mFrag.get().hFinishAddMarkers();
                    break;
                case MSG_ERROR_INFO:
                    String error = (String) msg.obj;
                    Log.e(TAG, error);
                    break;
                default:
                    break;
            }
        }
    }


    public void hFinishDecodeData() {
        hideProgressBar();
        if (mData == null || mData.status != GlobalResult.OK.getStatus()) {
            //返回值为空
            mFlagIsRefreshing = false;
            Toast.makeText(mContext, mData == null ? "" : mData.message,
                    Toast.LENGTH_SHORT).show();
        } else {
            //将数据加载到地图上
            resetMarkers(true);
        }
    }

    public void hFinishAddMarkers() {
        mFlagIsRefreshing = false;
        hideProgressBar();
    }

    @Override
    public boolean onMarkerClick(Marker marker) {
        Object obj = marker.getObject();
        if (obj instanceof JsonPointsOverview) {
            //显示Marker附加信息
            mCurrentPoint = (JsonPointsOverview) marker.getObject();
            showInfoWindow();
            return true;
        } else if (obj instanceof MarkerCluster) {
            hideInfoWindow();
            float zoom = aMap.getCameraPosition().zoom;
            if (zoom < ZOOM_LIMIT) {
                zoom += 3;
            }
            if (zoom > ZOOM_LIMIT) {
                zoom = ZOOM_LIMIT;
            }
            //移动视觉到中央
            aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
                    marker.getPosition(), zoom));
            return true;
        }
        return false;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.layout_city://选择城市
                chooseCity();
                break;
            case R.id.imagebutton_nearby:
                nearbyPoint();
                break;
            case R.id.fragmentmap_textview_search:
                searchPoint();
                break;
            case R.id.imagebutton_location: //重新定位
                relocation();
                break;
            case R.id.imageview_list: //充电点列表
                pointList();
                break;
            case R.id.imagebutton_filter:
                openFilterDialog();
                break;
            case R.id.textview_error:
            case R.id.refresh:
                refreshData();
                break;
            default:
                break;
        }
    }

    private void chooseCity() {
        Intent intent = new Intent(mContext, ActivityCityList.class);
        intent.putExtra(Const.CITY, mTextCity.getText());
        startActivityForResult(intent, Const.CODE_REQUEST_CITY);
    }

    private void nearbyPoint() {
        Intent intent = new Intent(mContext, ActivityPointList.class);
        intent.putExtra(ActivityPointList.KEY_MODEL, ActivityPointList.MODEL_NEARBY);
        startActivity(intent);
    }

    private void searchPoint() {
        Intent intent = new Intent(mContext, ActivityKeyWordSearch.class);//进入关键字搜索
        startActivity(intent);
    }

    private void pointList() {
        Intent intent = new Intent(mContext, ActivityPointList.class);
        startActivity(intent);
    }

    private void relocation() {
        if (mLocationClient != null) {
            isRepeatLocation = true;
            showProgressBar("正在重新定位");
        } else {
            AppContext ac = AppContext.getInstance();
            double lat = ac.getLat();
            double lng = ac.getLng();
            aMap.animateCamera(CameraUpdateFactory.changeLatLng(new LatLng(lat, lng)));
        }
    }

    private void openFilterDialog() {
        final DialogPointFilter d = new DialogPointFilter(mContext, mPointFilterModel);
        d.mFilter.setOnPointFilterListener(new PointFilter.OnPointFilterListener() {
            @Override
            public void onPointFilter() {
                d.dismiss();
                //重新绘制
                resetMarkers(false);
            }
        });
        d.show();
    }


    @Override
    public void onMapClick(LatLng arg0) {
        hideInfoWindow();//隐藏Marker信息窗口
    }

    //隐藏Marker信息窗口
    private void hideInfoWindow() {
    }

    //显示Marker信息窗口
    private void showInfoWindow() {
        //判断是否点击同一个Marker
        if (aMap.getCameraPosition().target.latitude == mCurrentPoint.lat
                && aMap.getCameraPosition().target.longitude == mCurrentPoint.lng) {
            Log.d(TAG, "showInfoWindow: the same location");

        } else {
            //将Marker移动地图到中心
            aMap.animateCamera(CameraUpdateFactory.changeLatLng(new LatLng(mCurrentPoint.lat, mCurrentPoint.lng)));
        }
        if (mCurrentPoint != null) {
            new DialogPointInfo(mContext, mCurrentPoint).show();
        }
    }

    @Override
    public void onCameraChange(CameraPosition arg0) {
    }

    /**
     * 上次的缩放等级<br/>
     * 注意：上次指的是操作过程中，操作完毕后 和 操作前 该参数指 当前缩放等级
     */
    private float mPreZoom = -1;
    /**
     * 临界点<br/>
     * 缩放级别越大，地图显示的范围越小
     */
    public final static float ZOOM_LIMIT = 12;
    /**
     * 执行聚合时候依赖的聚合等级<br/>
     * -1表示还没执行过聚合
     */
    private float mZoomTemp = -1;
    /**
     * 标志位：是否在执行点聚合操作
     */
    private boolean mFlagIsClustering = false;

    @Override
    public void onCameraChangeFinish(CameraPosition arg0) {
        Log.e(TAG, "onCameraChangeFinish: " + arg0.zoom);
        if (mData == null || mData.status != 0) {
            //如果数据没有准备好，直接返回
            mPreZoom = arg0.zoom;
        } else if (mPreZoom == -1) {
            //如果数据以及准备好，地图第一次移动相机，则无论如何也要添加点
            mPreZoom = arg0.zoom;
            resetMarkers(false);
        } else {
            //如果缩放级别没有发生变化，则不做任何处理
            if (mPreZoom != arg0.zoom) {
                if (mPreZoom >= ZOOM_LIMIT && arg0.zoom >= ZOOM_LIMIT) {
                    mPreZoom = arg0.zoom;
                } else if (arg0.zoom < ZOOM_LIMIT) {
                    mPreZoom = arg0.zoom;
                    resetMarkers(false);
                } else if (arg0.zoom >= ZOOM_LIMIT && mPreZoom < ZOOM_LIMIT) {
                    //发生了 边界跳跃
                    mPreZoom = arg0.zoom;
                    resetMarkers(false);
                }
            }
        }
    }

}